
package org.sopt.dev.ImgKnight.frontier.Database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;

import org.sopt.dev.ImgKnight.frontier.Filter.RabinHashFunction;

public class ToVisitDAO {

	private RabinHashFunction fp = null;
	
	private Logger exceptionLogger = null;
	
	private static Connection getConnection() {
		try {
			Class.forName("org.sqlite.JDBC");
			return DriverManager.getConnection("jdbc:sqlite:tovisit.db");
		} catch (ClassNotFoundException e) {
		} catch (SQLException e) {
		}
		return null;
	}
	
	public ToVisitDAO(boolean isCleanStart) {
		fp = new RabinHashFunction();
		exceptionLogger = Logger.getLogger("frontier.exception");
		
		Connection conn = null;
		Statement stat = null;
		try {
			conn = getConnection();
			if( conn != null ) {
				stat = conn.createStatement();
				if( isCleanStart )
					stat.executeUpdate("drop table if exists tovisit;");
				stat.executeUpdate("create table if not exists tovisit(RabinHashCode int primary key, Url varchar(200));");
			}
		} catch (Exception e) {
			exceptionLogger.fatal("Unexpected exception: "+e);
		} finally {
			if( stat != null ) try{ stat.close(); } catch(Exception e){}
			if( conn != null ) try{ conn.close(); } catch(Exception e){}
		}
	}
	
	public synchronized boolean insertTovisit(String[] tovisit) {
		Connection conn = null;
		PreparedStatement stat = null;
		try {
			conn = getConnection();
			if( conn != null ) {
				stat = conn.prepareStatement("insert into tovisit values(?,?);");
				for(String v : tovisit) {
					stat.setLong(1, fp.hash(v));
					stat.setString(2, v);
					stat.addBatch();
				}
				conn.setAutoCommit(false);
				stat.executeBatch();
				conn.setAutoCommit(true);
				return true;
			}
		} catch (Exception e) {
			//exceptionLogger.error("Unexpected exception: "+e);
		} finally {
			if( stat != null ) try{ stat.close(); } catch(Exception e){}
			if( conn != null ) try{ conn.close(); } catch(Exception e){}
		}
		return false;
	}
	
	public synchronized List<String> selectTovisitAndDelete(int rowSize) {
		List<String> tovisit = selectTovisit(rowSize);
		deleteTovisit(rowSize);
		return tovisit;
	}
	
	private synchronized List<String> selectTovisit(int rowSize) {
		List<String> tovisit = new Vector<String>(rowSize);
		Connection conn = null;
		PreparedStatement stat = null;
		ResultSet rs = null;
		try {
			conn = getConnection();
			if( conn != null ) {
				stat = conn.prepareStatement("select Url from tovisit order by RabinHashCode limit ?;");
				stat.setInt(1, rowSize);
				rs = stat.executeQuery();
				if( rs != null ) {
					while( rs.next() ) {
						tovisit.add(rs.getString("Url"));
					}
				}
			}
		} catch (Exception e) {
			exceptionLogger.error("Unexpected exception: "+e);
		} finally {
			if( rs != null ) try{ rs.close(); } catch(Exception e){}
			if( stat != null ) try{ stat.close(); } catch(Exception e){}
			if( conn != null ) try{ conn.close(); } catch(Exception e){}
		}
		return tovisit;
	}
	
	private synchronized void deleteTovisit(int rowSize) {
		Connection conn = null;
		PreparedStatement stat = null;
		try {
			conn = getConnection();
			if( conn != null ) {
				stat = conn.prepareStatement("delete from tovisit where RabinHashCode in (select RabinHashCode from tovisit order by RabinHashCode limit ?);");
				stat.setInt(1, rowSize);
				conn.setAutoCommit(false);
				stat.executeUpdate();
				conn.setAutoCommit(true);
			}
		} catch (Exception e) {
			exceptionLogger.error("Unexpected exception: "+e);
		} finally {
			if( stat != null ) try{ stat.close(); } catch(Exception e){}
			if( conn != null ) try{ conn.close(); } catch(Exception e){}
		}
	}
	
	public synchronized void deleteTovisitByRabinHashCode(String[] tovisit) {
		StringBuffer rabinHashCode = new StringBuffer();
		rabinHashCode.append("(");
		for(int i=0; i<tovisit.length; i++) {
			rabinHashCode.append(fp.hash(tovisit[i]));
			if( i < tovisit.length-1 )
				rabinHashCode.append(",");
			else
				rabinHashCode.append(")");
		}
		String query = "delete from tovisit where RabinHashCode in "+rabinHashCode.toString()+";";
		
		Connection conn = null;
		PreparedStatement stat = null;
		try {
			conn = getConnection();
			if( conn != null ) {
				stat = conn.prepareStatement(query);
				conn.setAutoCommit(false);
				stat.executeUpdate();
				conn.setAutoCommit(true);
			}
		} catch (Exception e) {
			exceptionLogger.error("Unexpected exception: "+e);
		} finally {
			if( stat != null ) try{ stat.close(); } catch(Exception e){}
			if( conn != null ) try{ conn.close(); } catch(Exception e){}
		}
	}
	
	public synchronized int selectTovisitSize() {
		Connection conn = null;
		PreparedStatement stat = null;
		ResultSet rs = null;
		int size = -1;
		try {
			conn = getConnection();
			if( conn != null ) {
				stat = conn.prepareStatement("select count(Url) as size from tovisit;");
				rs = stat.executeQuery();
				if( rs != null ) {
					if( rs.next() )
						size = rs.getInt("size");
				}
			}
		} catch (Exception e) {
			exceptionLogger.error("Unexpected exception: "+e);
		} finally {
			if( rs != null ) try{ rs.close(); } catch(Exception e){}
			if( stat != null ) try{ stat.close(); } catch(Exception e){}
			if( conn != null ) try{ conn.close(); } catch(Exception e){}
		}
		return size;
	}
	
}
